package com.tjbank.cssys.service.impl;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Valid;
import javax.validation.Validator;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.tjbank.cssys.framework.base.enums.YesOrNoEnum;
import com.tjbank.cssys.framework.base.exception.ServiceException;
import com.tjbank.cssys.framework.base.util.GeneratIDUtil;
import com.tjbank.cssys.api.RoleService;
import com.tjbank.cssys.api.TenantService;
import com.tjbank.cssys.dto.PostDTO;
import com.tjbank.cssys.dto.RoleDTO;
import com.tjbank.cssys.dto.TenanDTO;
import com.tjbank.cssys.dto.TenantDTO;
import com.tjbank.cssys.dto.TenantDetailsDTO;
import com.tjbank.cssys.mybatis.IamGroupDao;
import com.tjbank.cssys.mybatis.IamRoleDao;
import com.tjbank.cssys.mybatis.IamTenantDao;
import com.tjbank.cssys.mybatis.IamUserDao;
import com.tjbank.cssys.mybatis.entity.IamGroup;
import com.tjbank.cssys.mybatis.entity.IamRole;
import com.tjbank.cssys.mybatis.entity.IamTenant;
import com.tjbank.cssys.mybatis.entity.IamUser;
import com.tjbank.cssys.mybatis.sqlbuilder.IamGroupSqlBuilder;
import com.tjbank.cssys.mybatis.sqlbuilder.IamRoleSqlBuilder;
import com.tjbank.cssys.mybatis.sqlbuilder.IamTenantSqlBuilder;
import com.tjbank.cssys.mybatis.sqlbuilder.IamUserSqlBuilder;
import com.tjbank.cssys.service.convert.PostConvert;
import com.tjbank.cssys.service.convert.RoleConvert;
import com.tjbank.cssys.service.convert.TenantConvert;
import com.tjbank.cssys.service.enums.EntityTypeEnum;
import com.tjbank.cssys.service.util.Const;

/**
 * 租户
 * 
 * Package : com.tansun.magicube.iam.service.impl
 * 
 * @author -- lijiangtao 2020年5月4日 下午10:46:10
 *
 */
@Service
public class TenantServiceImpl implements TenantService {

    @Autowired
    private IamTenantDao tenantDao;

    @Autowired
    private IamGroupDao groupDao;

    @Autowired
    private IamUserDao userDao;

    @Autowired
    private IamRoleDao roleDao;

    @Autowired
    private Validator validator;

    @Autowired
    private RoleService roleService;

    /**
     * 新增租户信息
     * 
     * @param tenantDTO
     * @return
     * @author -- lijiangtao 2020年5月7日 下午6:06:22
     */
    @Override
    @Transactional
    public Integer addTenant(TenantDTO tenantDTO) {
        this.checkParam(tenantDTO);
        IamTenant entity = TenantConvert.INSTANCE.dtoToEntity(tenantDTO);
        entity.setId(GeneratIDUtil.getUUId());
        entity.setCreateTime(new Date());
        entity.setUpdateTime(new Date());
        this.setTreeRoot(entity);
        this.setRoleRoot(entity);
        return tenantDao.insert(entity);
    }

    /**
     * 设置树根
     * 
     * @param tenant
     * @param rootTree
     * @author -- lijiangtao 2020年7月21日 下午7:32:10
     */
    private void setTreeRoot(IamTenant tenant) {
        IamGroup entity = new IamGroup();
        entity.setId(GeneratIDUtil.getUUId());
        entity.setCode(tenant.getTenantCode());
        entity.setName(tenant.getTenantName());
        entity.setType(EntityTypeEnum.TENANT_TYPE.getCode());
        entity.setParentId(YesOrNoEnum.NO.getCode());
        entity.setLft(1);
        entity.setRgt(2);
        entity.setState(YesOrNoEnum.YES.getCode());
        entity.setTenantCode(tenant.getTenantCode());
        entity.setTenantName(tenant.getTenantName());
        entity.setCreateTime(new Date());
        entity.setIsDeleted(YesOrNoEnum.NO.getCode());
        groupDao.insert(entity);
    }

    /**
     * 设置角色
     * 
     * @param tenant
     * @author -- lijiangtao 2020年7月31日 下午12:31:56
     */
    private void setRoleRoot(IamTenant tenant) {
        RoleDTO roleDTO = new RoleDTO();
        roleDTO.setRoleName("系统管理员");
        roleDTO.setRoleAlias("admin");
        roleDTO.setTenantCode(tenant.getTenantCode());
        roleDTO.setTenantName(tenant.getTenantName());
        roleDTO.setState(YesOrNoEnum.YES.getCode());
        roleService.addRole(roleDTO);
    }

    /**
     * 分页查询租户信息
     * 
     * @param tenantDTO
     * @param pageable
     * @return
     * @author -- lijiangtao 2020年5月7日 下午5:40:55
     */
    @Override
    @SuppressWarnings("all")
    public Page<TenantDTO> queryTenant(TenantDTO tenantDTO, Pageable pageable) {
        IamTenantSqlBuilder sqlBuilder = this.setSqlBuilder(tenantDTO, pageable);
        List<IamTenant> tenanList = tenantDao.selectListBySqlBuilder(sqlBuilder);
        return new PageImpl(TenantConvert.INSTANCE.entitiesToDtoList(tenanList), pageable, tenantDao.countBySqlBuilder(sqlBuilder));
    }

    /**
     * setSqlBuilder
     * 
     * @param tenantDTO
     * @param pageable
     * @author -- lijiangtao 2020年5月7日 下午6:13:35
     */
    private IamTenantSqlBuilder setSqlBuilder(TenantDTO tenantDTO, Pageable pageable) {
        IamTenantSqlBuilder sqlBuilder = new IamTenantSqlBuilder();
        sqlBuilder.setPageSize(pageable.getPageSize());
        sqlBuilder.setIndexNo((int) pageable.getOffset());
        if (StringUtils.isNotBlank(tenantDTO.getTenantCode())) {
            sqlBuilder.andTenantCodeLikeBoth(tenantDTO.getTenantCode());
        }
        if (StringUtils.isNotBlank(tenantDTO.getTenantName())) {
            sqlBuilder.andTenantNameLikeBoth(tenantDTO.getTenantName());
        }
        if (StringUtils.isNotBlank(tenantDTO.getTenantState())) {
            sqlBuilder.andTenantStateEqualTo(tenantDTO.getTenantState());
        }
        if (Objects.deepEquals(tenantDTO.getTenantCode(), Const.ROOT_TENANT_CODE)) {
            sqlBuilder.andTenantCodeEqualTo(tenantDTO.getTenantCode());
        }
        sqlBuilder.orderByUpdateTime(true).setAutoFilterNull(true);
        return sqlBuilder;
    }

    /**
     * 更新
     * 
     * @param tenantDTO
     * @return
     * @author -- lijiangtao 2020年5月7日 下午6:06:27
     */
    @Override
    @Transactional
    public Integer updateTenant(TenantDTO tenantDTO) {
        this.checkTenantId(tenantDTO.getId());
        IamTenant entity = TenantConvert.INSTANCE.dtoToEntity(tenantDTO);
        entity.setUpdateTime(new Date());
        IamTenantSqlBuilder sqlBuilder = new IamTenantSqlBuilder();
        sqlBuilder.andIdEqualTo(entity.getId());
        this.updateState(tenantDTO);
        this.updateGroupTenantName(entity);
        this.updateUserTenantName(entity);
        this.updateRoleTenantName(entity);
        return tenantDao.updateBySqlBuilderSelective(entity, sqlBuilder);
    }

    /**
     * 修改租表租户名称
     * 
     * @param entity
     * @author -- lijiangtao 2020年7月29日 下午5:21:44
     */
    private void updateGroupTenantName(IamTenant entity) {
        // T
        IamGroupSqlBuilder groupSqlBuilder = new IamGroupSqlBuilder();
        groupSqlBuilder.andTenantCodeEqualTo(entity.getTenantCode()).andTypeEqualTo(EntityTypeEnum.TENANT_TYPE.getCode());
        IamGroup iamGroup = new IamGroup();
        iamGroup.setName(entity.getTenantName());
        groupDao.updateBySqlBuilderSelective(iamGroup, groupSqlBuilder);

        // O
        IamGroupSqlBuilder sqlBuilder = new IamGroupSqlBuilder();
        sqlBuilder.andTenantCodeEqualTo(entity.getTenantCode());
        IamGroup group = new IamGroup();
        group.setTenantName(entity.getTenantName());
        groupDao.updateBySqlBuilderSelective(group, sqlBuilder);
    }

    /**
     * 修改用户表租户名称
     * 
     * @param entity
     * @author -- lijiangtao 2020年7月29日 下午5:21:44
     */
    private void updateUserTenantName(IamTenant entity) {
        IamUserSqlBuilder sqlBuilder = new IamUserSqlBuilder();
        sqlBuilder.andTenantCodeEqualTo(entity.getTenantCode());
        IamUser user = new IamUser();
        user.setTenantName(entity.getTenantName());
        userDao.updateBySqlBuilderSelective(user, sqlBuilder);
    }

    /**
     * 修改角色表租户名称
     * 
     * @param entity
     * @author -- lijiangtao 2020年7月29日 下午5:21:44
     */
    private void updateRoleTenantName(IamTenant entity) {
        IamRoleSqlBuilder sqlBuilder = new IamRoleSqlBuilder();
        sqlBuilder.andTenantCodeEqualTo(entity.getTenantCode());
        IamRole role = new IamRole();
        role.setTenantName(entity.getTenantName());
        roleDao.updateBySqlBuilderSelective(role, sqlBuilder);
    }

    /**
     * 更新启用状态
     * 
     * 禁用租户
     * 
     * 用户、角色、组
     * 
     * 
     * @param tenantDTO
     * @author -- lijiangtao 2020年7月24日 下午3:11:35
     */
    private void updateState(TenantDTO tenantDTO) {
        IamGroup entity = new IamGroup();
        entity.setUpdateTime(new Date());
        IamGroupSqlBuilder sqlBuilder = new IamGroupSqlBuilder();
        sqlBuilder.andTenantCodeEqualTo(tenantDTO.getTenantCode());
        if (Objects.deepEquals(tenantDTO.getTenantState(), YesOrNoEnum.YES.getCode())) {
            entity.setState(YesOrNoEnum.YES.getCode());
            groupDao.updateBySqlBuilderSelective(entity, sqlBuilder);
        } else {
            entity.setState(YesOrNoEnum.NO.getCode());
            groupDao.updateBySqlBuilderSelective(entity, sqlBuilder);
        }
    }

    /**
     * 查询已启用的租户
     * 
     * @return
     * @author -- lijiangtao 2020年7月6日 下午5:51:09
     */
    @Override
    public List<TenanDTO> queryTenant() {
        IamTenantSqlBuilder sqlBuilder = new IamTenantSqlBuilder();
        sqlBuilder.andTenantStateEqualTo(YesOrNoEnum.YES.getCode()).andIsDeletedEqualTo(YesOrNoEnum.NO.getCode());
        return TenantConvert.INSTANCE.entitiesToTenantList(tenantDao.selectListBySqlBuilder(sqlBuilder));
    }

    /**
     * 选择租户
     * 
     * @param tenantCode
     * @return
     * @author -- lijiangtao 2020年7月22日 下午12:38:07
     */
    @Override
    public List<TenanDTO> queryTenant(String tenantCode) {
        IamTenantSqlBuilder sqlBuilder = new IamTenantSqlBuilder();
        if (!Objects.deepEquals(tenantCode, Const.ROOT_TENANT_CODE)) {
            sqlBuilder.andTenantCodeEqualTo(tenantCode);
        }
        sqlBuilder.andTenantStateEqualTo(YesOrNoEnum.YES.getCode()).andIsDeletedEqualTo(YesOrNoEnum.NO.getCode());
        return TenantConvert.INSTANCE.entitiesToTenantList(tenantDao.selectListBySqlBuilder(sqlBuilder));
    }

    /**
     * 根据租户Code查询
     * 
     * @param tenantCode
     * @return
     * @author -- lijiangtao 2020年7月10日 下午2:29:55
     */
    @Override
    public TenantDetailsDTO queryObjByTenantCode(String tenantCode) {
        TenantDetailsDTO tenantDetailsDTO = new TenantDetailsDTO();
        tenantDetailsDTO.setPostList(this.queryPostByTenantCode(tenantCode)).setRoleList(this.queryRoleByTenantCode(tenantCode));
        return tenantDetailsDTO;
    }

    /**
     * 根据租户Code查询岗位信息
     * 
     * @param tenantCode
     * @return
     * @author -- lijiangtao 2020年7月10日 下午2:37:17
     */
    private List<PostDTO> queryPostByTenantCode(String tenantCode) {
        IamGroupSqlBuilder sqlBuilder = new IamGroupSqlBuilder();
        sqlBuilder.andTenantCodeEqualTo(tenantCode).andIsDeletedEqualTo(YesOrNoEnum.NO.getCode());
        sqlBuilder.andStateEqualTo(YesOrNoEnum.YES.getCode()).andTypeEqualTo(EntityTypeEnum.POST_TYPE.getCode());
        return PostConvert.INSTANCE.entitiesToDtoList(groupDao.selectListBySqlBuilder(sqlBuilder));
    }

    /**
     * 根据租户Code查询角色信息
     * 
     * @param tenantCode
     * @return
     * @author -- lijiangtao 2020年7月10日 下午2:38:44
     */
    private List<RoleDTO> queryRoleByTenantCode(String tenantCode) {
        IamRoleSqlBuilder sqlBuilder = new IamRoleSqlBuilder();
        sqlBuilder.andTenantCodeEqualTo(tenantCode).andIsDeletedEqualTo(YesOrNoEnum.NO.getCode());
        return RoleConvert.INSTANCE.entitiesToDtoList(roleDao.selectListBySqlBuilder(sqlBuilder));
    }

    /**
     * 校验租户ID
     * 
     * @param tenantId
     * @author -- lijiangtao 2020年6月15日 下午9:10:09
     */
    private void checkTenantId(String tenantId) {
        if (StringUtils.isBlank(tenantId)) {
            throw new ServiceException("租户ID不能为空");
        }
    }

    /**
     * 参数校验
     * 
     * @param tenantDTO
     * @author -- lijiangtao 2020年6月18日 下午7:46:52
     */
    private void checkParam(TenantDTO tenantDTO) {
        Set<ConstraintViolation<@Valid TenantDTO>> validate = validator.validate(tenantDTO);
        if (!validate.isEmpty()) {
            for (ConstraintViolation<TenantDTO> constraintViolation : validate) {
                throw new ServiceException(constraintViolation.getMessage());
            }
        }
    }
}
